package org.c41.graphics.swing;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.util.ArrayList;

import javax.swing.JPanel;

public class JGridPanel extends JPanel {

	public JGridPanel(int iwidth, int iheight){
		setLayout(new C41GridLayout(iwidth,iheight));
	}

	public void add(Component comp, int ix, int iy, int iwidth, int iheight){
		super.add(comp, new C41ComponentMap(comp, ix, iy, iwidth, iheight));
	}

	public Component getComponent(int ix, int iy){
		return ((C41GridLayout)getLayout()).inner_getComponent(ix,iy);
	}

}

class C41ComponentMap{

	final Component component;
	final int ix,iy,iwidth,iheight;

	C41ComponentMap(Component comp, int ix, int iy, int iwidth, int iheight) {
		this.component=comp;
		this.ix=ix;
		this.iy=iy;
		this.iwidth=iwidth;
		this.iheight=iheight;
	}

}

class C41GridLayout implements LayoutManager2{

	private int iwidth;
	private int iheight;
	private ArrayList<C41ComponentMap> map = new ArrayList<>();

	C41GridLayout(int iwidth, int iheight) {
		this.iwidth=iwidth;
		this.iheight=iheight;
	}

	Component inner_getComponent(int ix, int iy) {
		for(C41ComponentMap m:map){
			if(m.ix<=ix&&m.ix+m.iwidth>ix&&m.iy<=iy&&m.iy+m.iheight>iy){
				return m.component;
			}
		}
		return null;
	}

	@Override
	public void addLayoutComponent(String name, Component comp) {
		addLayoutComponent(comp, null);
	}

	@Override
	public void removeLayoutComponent(Component comp) {
		for(C41ComponentMap m : map){
			if(m.component==comp){
				map.remove(m);
				return;
			}
		}
	}

	@Override
	public Dimension preferredLayoutSize(Container parent) {
		Insets insets = parent.getInsets();
		int ncomponents = parent.getComponentCount();
		int nrows = iheight;
		int ncols = iwidth;

		if (nrows > 0) {
			ncols = (ncomponents + nrows - 1) / nrows;
		} else {
			nrows = (ncomponents + ncols - 1) / ncols;
		}
		int w = 0;
		int h = 0;
		for (int i = 0 ; i < ncomponents ; i++) {
			Component comp = parent.getComponent(i);
			Dimension d = comp.getPreferredSize();
			if (w < d.width) {
				w = d.width;
			}
			if (h < d.height) {
				h = d.height;
			}
		}
		return new Dimension(insets.left + insets.right + ncols*w,
				insets.top + insets.bottom + nrows*h);
	}

	@Override
	public Dimension minimumLayoutSize(Container parent) {
		Insets insets = parent.getInsets();
		int ncomponents = parent.getComponentCount();
		int nrows = iheight;
		int ncols = iwidth;

		if (nrows > 0) {
			ncols = (ncomponents + nrows - 1) / nrows;
		} else {
			nrows = (ncomponents + ncols - 1) / ncols;
		}
		int w = 0;
		int h = 0;
		for (int i = 0 ; i < ncomponents ; i++) {
			Component comp = parent.getComponent(i);
			Dimension d = comp.getMinimumSize();
			if (w < d.width) {
				w = d.width;
			}
			if (h < d.height) {
				h = d.height;
			}
		}
		return new Dimension(insets.left + insets.right + ncols*w,
				insets.top + insets.bottom + nrows*h);
	}

	@Override
	public void layoutContainer(Container parent){
		int w = parent.getWidth()/iwidth;
		int h = parent.getHeight()/iheight;
		for(C41ComponentMap m:map){
			m.component.setBounds(m.ix*w, m.iy*h, m.iwidth*w, m.iheight*h);
			if(m.ix+m.iwidth==iwidth){
				m.component.setSize(parent.getWidth()-m.ix*w, m.component.getHeight());
			}
			if(m.iy+m.iheight==iheight){
				m.component.setSize(m.component.getWidth(),parent.getHeight()-m.iy*h);
			}
		}
	}

	@Override
	public void addLayoutComponent(Component comp, Object constraints) {
		if(constraints!=null){
			C41ComponentMap map = (C41ComponentMap)constraints;
			this.map.add(map);
		}
		else{
			for(int j=0;j<iheight;j++){
				for(int i=0;i<iwidth;i++){
					if(inner_getComponent(i, j)==null){
						this.map.add(new C41ComponentMap(comp, i, j, 1, 1));
						return;
					}
				}
			}
		}
	}

	@Override
	public Dimension maximumLayoutSize(Container target) {
		return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
	}

	@Override
	public float getLayoutAlignmentX(Container target) {
		return 0.0f;
	}

	@Override
	public float getLayoutAlignmentY(Container target) {
		return 0.0f;
	}

	@Override
	public void invalidateLayout(Container target) {
	}

}
